根據Android Studio
網站對於Room
的說法:
Room is a Database Object Mapping library that makes it easy to access database on Android applications.
簡單來說是一個將資料儲存在手機的本地資料庫且可以方便存取的功能,這個功能是SQLite提供的抽象層。
這些依賴可以到Android Developers網站的Room頁面搜尋到最新版本。
//ROOM (遇到了大概是版本的問題,換了新版本就沒問題了)
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// optional - Paging 3 Integration
implementation "androidx.room:room-paging:2.5.0-alpha02"
Database是抽象類別
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
/**
透過Database類別中的entities陣列來引用MyData的實體類別
資料綁定的Getter-Setter,資料庫版本,是否將資料導出至文件
**/
@Database(entities = {MyData.class},version = 1,exportSchema = true)
public abstract class DataBase extends RoomDatabase {
public static final String DB_NAME = "DB001.db"; //資料庫名稱,可以自訂
private static volatile DataBase instance;
public static synchronized DataBase getInstance(Context context){
if(instance == null){
instance = create(context); //創立新的資料庫
}
return instance;
}
private static DataBase create(final Context context){
return Room.databaseBuilder(context,DataBase.class,DB_NAME).build();
}
public abstract DataUao getDataUao(); //設置對外接口
}
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
@Dao
public interface DataUao {
//定義資料庫
String tableName = "MyTable01";
/**=======================================================================================*/
/**簡易新增所有資料的方法*/
@Insert(onConflict = OnConflictStrategy.REPLACE)//預設萬一執行出錯,REPLACE為覆蓋
void insertData(MyData myData);
/**複雜(?)新增所有資料的方法*/
@Query("INSERT INTO "+tableName+"(name,Age,Hobby,Email) VALUES(:name,:Age,:Hobby,:Email)")
void insertData(String name,String Age,String Hobby,String Email);
/**=======================================================================================*/
/**撈取全部資料*/
//**
// 在要監聽的資料上建立Observable。
// /
@Query("SELECT * FROM " + tableName)
List<MyData> displayAll();
/**撈取某個名字的相關資料*/
@Query("SELECT * FROM " + tableName +" WHERE id = :id")
List<MyData> findDataByName(String id);
/**=======================================================================================*/
/**簡易更新資料的方法*/
@Update
void updateData(MyData myData);
/**複雜(?)更新資料的方法*/
@Query("UPDATE "+tableName+" SET name = :name,Age=:Age,Hobby=:Hobby,Email = :Email WHERE id = :id" )
void updateData(int id,String name,String Age,String Hobby,String Email);
/**=======================================================================================*/
/**簡單刪除資料的方法*/
@Delete
void deleteData(MyData myData);
/**複雜(?)刪除資料的方法*/
@Query("DELETE FROM " + tableName + " WHERE id = :id")
void deleteData(int id);
}
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
//** ****TableName****
// Room預設使用類別名稱作為資料表名稱,若想要資料表使用不同名稱
// 可以設定@Entity註釋的tableName屬性。
// ###資料表名稱是區分大小寫###
//
// 類似於 tableName的功能,Room 使用屬性名稱作為資料庫中的列名稱。如果希望列具有不同的名稱,請將 @ColumnInfo 註釋加到屬性中。
// /
@Entity(tableName = "MyTable01") //這邊要先取好table的名字,稍後的table設置必須與他相同
public class MyData {
//** @PrimaryKey
// 每個實體類別必須至少定義一個主鍵,即使只有一個屬性也須加上@PrimaryKey註釋來註釋該屬性
// 若希望Room可以為實體自動分配ID,則可設定@PrimaryKey的autoGenerate屬性
// /
@PrimaryKey(autoGenerate = true) //設置是否使ID自動累加
private int id;
private String name;
private String Age;
private String Hobby;
private String Email;
public MyData(String name, String Age, String Hobby, String Email) {
this.name = name;
this.Age = Age;
this.Hobby = Hobby;
this.Email = Email;
}
//若實體具有不想被保存的屬性,則可使用@Ignore註釋
@Ignore//如果要使用多形的建構子,必須加入@Ignore
public MyData(int id, String name, String Age, String Hobby, String Email) {
this.id = id;
this.name = name;
this.Age = Age;
this.Hobby = Hobby;
this.Email = Email;
}
//**
// Getter-Setter 類別
// "在學習物件導向程式語言的時候,每個人一定都有寫到getter與setter的經驗。"
//
// getter-setter是用來作為物件的私有(private)變數或屬性(field)的公用存取介面(public access interface),
// 也就是宣告兩個public method,
// 一個為getter用來取得private varible,
// 另一個則為setter用來設定private varible。
//
// 這樣的設計目的是為了避免private variable被不當使用,
// 像是可以在setter的設定時可加入一些條件判別或處理來避免變數被設成 unacceptable value。
//
// /
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return Age;
}
public void setAge(String Age) {
this.Age = Age;
}
public String getHobby() {
return Hobby;
}
public void setHobby(String Hobby) {
this.Hobby = Hobby;
}
public String getEmail() {
return Email;
}
public void setEmail(String Email) {
this.Email = Email;
}
}
這邊我會建立一個java物件的Adapter轉接器,在這邊先建立功能在這裡然後再導向到主程式內部。這個功用就是在往後一個程式容量越來越大後若有相同方法就可以再次使用這個物件。
/**更新資料*/
public void refreshView() {
new Thread(()->{
List<Entity> data = DataBase.getInstance (activity).getDataUao().displayAll();
this.entities = data;
activity.runOnUiThread(() -> {
notifyDataSetChanged();
});
}).start();
}
/**刪除資料*/
public void deleteData(int position){
new Thread(()->{
DataBase.getInstance(activity).getDataUao().deleteData(entities.get(position).getId());
activity.runOnUiThread(()->{
notifyItemRemoved(position);
refreshView();
});
}).start();
}
private List<Entity> entities;
private Activity activity;
private OnItemClickListener onItemClickListener;
//Adapter
public Adapter(Activity activities){
this.activity = activities;
}
//Entity
public void setData(List<Entity> entities){
this.entities = entities;
notifyDataSetChanged ();
}
//Interface-OnItemClickListener
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
interface的用處是可以在不同的物件之間進行呼叫。
public interface OnItemClickListener {
void onItemClick(Entity entity);
}
//設定更改資料的事件
btModify.setOnClickListener((view) ->{
new Thread(() -> {
if (nowSelectedData ==null) {
runOnUiThread (()->{
Toast.makeText (MainActivity2.this,"尚未選擇更改資料",Toast.LENGTH_SHORT).show ();
});
return;
}
String name = editName.getText().toString();
String Age = editAge.getText().toString();
String Hobby = editHobby.getText().toString();
String Email = editEmail.getText().toString();
Entity data = new Entity (nowSelectedData.getId(),name,Age,Hobby,Email);
DataBase.getInstance(this).getDataUao().updateData(data);
runOnUiThread(()->{
editName.setText("");
editAge.setText("");
editEmail.setText("");
editHobby.setText("");
nowSelectedData = null;
myAdapter.refreshView();
Toast.makeText(this,"已更新資訊!",Toast.LENGTH_LONG).show();
});
}).start();
});
//清空填寫資料事件按鈕
btClear.setOnClickListener((view -> {
String name = editName.getText().toString();
String Age = editAge.getText().toString();
String Hobby = editHobby.getText().toString();
String Email = editEmail.getText().toString();
if (name.length() == 0 && Age.length () == 0 && Hobby.length () == 0 && Email.length () == 0) {
//偵測尚未輸入姓名資料時Toast。
runOnUiThread (()->{
Toast.makeText (MainActivity2.this,"尚未填入資料",Toast.LENGTH_SHORT).show ();
});
return;
}
editName.setText("");
editAge.setText("");
editHobby.setText("");
editEmail.setText("");
nowSelectedData = null;
Toast.makeText (MainActivity2.this,"已清空填寫資料",Toast.LENGTH_SHORT).show ();
}));
/**新增資料**/
btCreate.setOnClickListener((view -> {
new Thread(() -> {
String name = editName.getText().toString();
String Age = editAge.getText().toString();
String Hobby = editHobby.getText().toString();
String Email = editEmail.getText().toString();
if (name.length() == 0 || Age.length () ==0 || Hobby.length () == 0 || Email.length () == 0) {
//偵測尚未輸入姓名資料時Toast。
runOnUiThread (()->{
Toast.makeText (MainActivity2.this,"資料輸入不完整",Toast.LENGTH_SHORT).show ();
});
return;
}
Entity data = new Entity(name,Age,Hobby,Email);
DataBase.getInstance(this).getDataUao().insertData(data);
refrashed();
runOnUiThread(()->{
myAdapter.refreshView();
//建立完成後TextView清空輸入資料
editName.setText("");
editAge.setText("");
editHobby.setText("");
editEmail.setText("");
});
}).start();
}));
btRefresh.setOnClickListener(View -> {
new Thread(()->{
DataBase.getInstance(this).getDataUao().displayAll();
refrashed();
runOnUiThread(()->{
myAdapter.refreshView();
});
}).start();
});
//初始化RecyclerView的表格副程式
public void refrashed(){
// new Thread(()->{ //這邊已經在一個Thread中了,因此若在主程式中再宣告進另一個Thread中會有問題。
List<Entity> data = DataBase.getInstance(this).getDataUao().displayAll();
runOnUiThread(()->{
recyclerView.setAdapter(myAdapter);
myAdapter.setData(data);
myAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(Entity myData) {
}
});
//**
// 取得在RecyclerView被選取的資料表欄位並顯示在上方的欄位中。
// /
myAdapter.setOnItemClickListener((myData) -> {
nowSelectedData = myData;
editName.setText(myData.getName());
editAge.setText(myData.getAge());
editHobby.setText(myData.getHobby());
editEmail.setText(myData.getEmail());
});
});
// });